package org.example.uhy.mvc;

import org.example.uhy.application.exceptions.AuthenticationException;
import org.example.uhy.exceptions.BusinessException;
import org.example.uhy.openapi.dto.ResponseDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * 统一异常处理类
 */
public class UhyHandlerExceptionResolver implements HandlerExceptionResolver {
    Logger logger = LoggerFactory.getLogger(UhyHandlerExceptionResolver.class);

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if (ex instanceof AuthenticationException) {
            ResponseDto responseDto = ResponseDto.failed(ex.getMessage()).withData(getLoginRedirectPath(request));
            responseDto.setCode(String.valueOf(HttpStatus.UNAUTHORIZED.value()));
            return buildJsonModelAndView(responseDto);
        } else {
            ResponseDto responseDto = createErrorResponseDto(request, ex);
            // 这里可以发送消息
//            ServiceContext serviceContext = (ServiceContext) request.getAttribute(SmsConstants.SERVICE_CONTEXT);
//            if (serviceContext != null && serviceContext.getRequestData() instanceof SmsBaseInfo) {
//                SmsBaseInfo smsBaseInfo = (SmsBaseInfo) serviceContext.getRequestData();
//                // failed monitor
//                monitorService.addRequestFailedCount(smsBaseInfo.appCustomerId());
//                // failed event
//                RequestFailedEvent event = new RequestFailedEvent(smsBaseInfo.appCustomerId());
//                event.setMessage(ex.getMessage());
//                eventPublisher.publishSafe(event);
//            }
            return buildJsonModelAndView(responseDto);
        }
    }

    private ResponseDto createErrorResponseDto(HttpServletRequest request, Throwable ex) {
        String msg = null;
        String errorCode = null;
        if (ex instanceof DuplicateKeyException) {
            msg = "该数据已经存在";
            errorCode = "duplicate_key";
        } else if (ex instanceof DataAccessException) {
            msg = "数据访问异常";
            errorCode = "data_access_failed";
        } else {
            msg = getMessage(ex);
            if (msg != null) {
                msg = msg.replaceFirst("^.*?Exception:\\s*", "");
            }
        }
        if (ex instanceof BusinessException) {
            logger.warn("pathInfo: {}, msg: {}", request.getRequestURI(), msg);
        } else {
            logger.error(msg, ex);
        }
        ResponseDto responseDto = ResponseDto.failed(msg);
        return responseDto;
    }

    private ModelAndView buildJsonModelAndView(Object data) {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("responseData", data);
        ModelAndView mav = new ModelAndView();
        mav.setStatus(HttpStatus.OK);
        MappingJackson2JsonView view = new MappingJackson2JsonView();
        view.setAttributesMap(resultMap);
        view.setExtractValueFromSingleKeyModel(true);
        // view.setModelKey("responseData");
        mav.setView(view);
        return mav;
    }

    private String getLoginRedirectPath(HttpServletRequest request) {
        String userAgent = request.getHeader(HttpHeaders.USER_AGENT);
        if (userAgent != null && userAgent.contains("Mobile")) {
            return "the-mobile-login-url";
            // return loginProperties.getPages().get("m-login");
        } else {
            return "the-pc-login-url";
            // return loginProperties.getPages().get("login");
        }
    }

    public static String getMessage(Throwable th) {
        if (th == null) {
            return "";
        } else {
            String clsName = th.getClass().getSimpleName();
            String msg = th.getMessage();
            return clsName + ": " + msg;
        }
    }
}